import java.io.*;
import java.net.*;
import java.text.DecimalFormat;
import java.util.ArrayList;

//Fuer jeden Client eine eigene Session bzw. Thread
public class ClientSession extends Thread {
	private Socket s;
	private InputStream in;
	private OutputStream out;
	private UserDB userdb;
	private User loginuser;
	private ObjectOutputStream outToClient;
	private ObjectInputStream inFromClient;
	private String bline = "";
	private AuctionManager auctman;
	private DecimalFormat f;
	private ArrayList<ClientSession> sessionDB;
	private int udpport;
	
	
	public ClientSession (Socket s,UserDB userdb,AuctionManager auctman,ArrayList<ClientSession>sessionDB)throws IOException{
		this.s=s;
		this.in = s.getInputStream();
		this.out = s.getOutputStream();
		this.userdb = userdb;
		this.auctman = auctman;
		this.f = new DecimalFormat("#0.00"); 
		this.sessionDB= sessionDB;
		
	}
	public void run(){
			String clientSentence;
			boolean chklogin=false;
			udpport=0;
			try{
				// I/O Streams Client-Server
				inFromClient = new ObjectInputStream(in);
				outToClient = new ObjectOutputStream(out);
			}
			catch (IOException e){
				System.out.println("Error Creating In/OutputStream");
				return;
			}
		
			try {
				//Konvertiert String zu Int fuer UDPPort
				udpport = Integer.parseInt(((Messagepk)(inFromClient.readObject())).getMessage().get(0));} 
			catch (NumberFormatException e1) {e1.printStackTrace();return;} 
			catch (IOException e1) {e1.printStackTrace();return;} 
			catch (ClassNotFoundException e1) {e1.printStackTrace();return;}
			
			while (true){
				try{

					clientSentence=null;
					try {
						//Objekt vom Client
						clientSentence =((Messagepk)(inFromClient.readObject())).getMessage().get(0);
					} catch (IOException e) {
						System.out.println("Client disconnected from Server");
						break;
					} catch (ClassNotFoundException e) {e.printStackTrace();break;}
					
					
					if (clientSentence!=null){
						//Splitte String auf
						SplittLine line = new SplittLine(clientSentence);
						
						while (line.hasNext()){
							String cmd = line.readNext();
							
							//Ueberpruefung auf !login
							if (cmd.equals("!login")){
								if(!chklogin){
									if(line.hasNext()){
										
										String username = line.readNext();
										//Falls weitere Parameter vorhanden sind
										if(line.hasNext()){outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));break;}
										//holt User aus der DB
										loginuser = userdb.getUser(username);
										if(!(loginuser.isLoggedin())){
											//Setze User IP
											loginuser.setIP(s.getInetAddress());
		
											//Setze User UDPPort
											//assert udpport !=0;
											loginuser.setPort(udpport);
											//Fuer Ausgabe Name des Users
											bline = loginuser.getName();
											//Sende Objekt an Client
											outToClient.writeObject(new Messagepk(bline,"Successfully logged in as "+loginuser.getName()+"!"));
											//Flag, User ist nun eingelogged
											loginuser.setLoggedin(true);
											
											//Sende zwischengespeicherte Notifications
											loginuser.sendNotifications();
											chklogin = true;
										}
										else{
											loginuser=null;
											outToClient.writeObject(new Messagepk(bline,"Login rejected! User is already connected" ));			
										}
									}
									else{outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));break;}
								}
								else{outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));break;}
								
								
							}
							//Ueberpruefung auf !list
							else if(cmd.equals("!list")){
								
								//Sendet Liste aus AuctionManager an Client
								ArrayList<Auction> auctlist = auctman.getAuctlist();
								Messagepk listmsg = new Messagepk();
								for (int i=0;i<auctlist.size();i++){
									Auction markedAuct = auctlist.get(i);
									listmsg.addMessage((markedAuct.getId()+". '"+ markedAuct.getDescription()+
											"' "+markedAuct.getCreatorName()+" " + markedAuct.getEnd()+" "+f.format(markedAuct.getHBit())+" "+markedAuct.getHBitUserName())) ;
								}
								listmsg.setUsername(bline);
								outToClient.writeObject(listmsg);
							}
							
							else if(cmd.equals("!logout")){
								if (!chklogin){
									//Falls nicht eingelogged
									outToClient.writeObject(new Messagepk(bline,"You have to log in first!"));
								}
								else{
									bline = "";
									outToClient.writeObject(new Messagepk(bline,"Successfully logged out as "+ loginuser.getName()));
									loginuser.setLoggedin(false);
									chklogin=false;
								}
							}
							//Ueberpruefung auf !create
							else if(cmd.equals("!create")){
								
								int duration=0;
								String description="";
								//Ob User eingelogged
								if (!chklogin){
									outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
									break;
								}
								else{
									
									if(line.hasNext()){
										//Parameter Pruefung
										try{
											duration= Integer.parseInt(line.readNext());
										}
										catch(NumberFormatException e){
											outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
											break;
										}
											if(line.hasNext()){
												description =line.readNext();
												while (line.hasNext()){
													description +=" "+line.readNext();
												}
												//Erstelle Neue Auktion und Message an User
												outToClient.writeObject(new Messagepk(bline,auctman.createAuction(duration, description, loginuser)));
											}
											else{
												//Falscher Parameter
												outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
												break;
											}
									}
									else{
										//Falscher Parameter
										outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
										break;
									}
								}
							}
							//Ueberpruefe auf !bid
							else if(cmd.equals("!bid")){
								int auctId=0;
								double mount=0;
								
								//Ob User eingelogged
								if (!chklogin){
									outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
									break;
								}
								else{
									
									if(line.hasNext()){
										try{
											auctId= Integer.parseInt(line.readNext());
										}
										catch(NumberFormatException e){
											//Falscher Parameter
											outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
											break;
										}
										if(line.hasNext()){
											try{
												mount= Double.parseDouble(line.readNext());
											}
											catch(NumberFormatException e){
												//Falscher Parameter
												outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
												break;
											}
											Auction auct = auctman.getAuct(auctId);
											if(auct==null){
												//gweuenschte Auktion ist nicht verfuegbar
												outToClient.writeObject(new Messagepk(bline,"Auction with ID "+auctId+" is not available!"));
												break;
											}
											if(auct.bid(mount, loginuser)){
												//Erfolgreich geboten
												outToClient.writeObject(new Messagepk(bline,"You successfully bid with " +f.format(mount)+ " on "+auct.getDescription()+"."));
											}
											else{
												//Gebot war zu niedrig
												outToClient.writeObject(new Messagepk(bline,"You unsuccessfully bid with " +f.format(mount)+ " on "+auct.getDescription()+".Current highest bid is "+f.format(auct.getHBit())+"."));
											}		
										}
										else{
											//Falscher Parameter
											outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
											break;
										}
									}
									else{
										//Falscher Parameter
										outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
										break;
									}
								}
							}
							else{
								//Falscher Parameter
								outToClient.writeObject(new Messagepk(bline,"Unkown Command!"));
								break;
							}							
						}
						
					}
				}
				catch (IOException e){
					//Client disconnected
					loginuser.setLoggedin(false);
					sessionDB.remove(sessionDB.indexOf(this));
					System.out.println("Client disconnected from Server");
					break;
				}
			}

	}
	//Sendet die Shutdownnotifikation an den Client
	public void sendShutdownNotification(){
		new Notification(udpport,"!shutdown",s.getInetAddress());
	}
	//Schliesst bei shutdown die Streams
	public void closeStreams(){
		try {this.in.close();} catch (IOException e1){e1.printStackTrace();}
		try {this.out.close();} catch (IOException e) {e.printStackTrace();}
	}



}
